home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Toolbox / Balloony / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-16  |  14.6 KB  |  601 lines  |  [TEXT/KAHL]

  1. /* main.c - main file of Balloonify
  2.     November 11, 1996: I, David Phillip Oster, place this source code in the public
  3.         domain. This means you can do anyhing you want with it.
  4.     It would be considerate if you kept me posted on any bugs, bug fixes, or
  5.     improvements.
  6.     oster@netcom.com
  7.  */
  8. #include "Balloonify.h"
  9. #include "BalloonyRes.h"
  10.  
  11. /* kFileMenu -  items
  12.  */
  13. enum {
  14.     kOpenI = 1,
  15.     kQuitI = kOpenI + kSkipGrayLine
  16. };
  17.  
  18. /* kEditMenu -  items
  19.  */
  20. enum {
  21.     kUndoI = 1,
  22.     kCutI = kUndoI + kSkipGrayLine,
  23.     kCopyI,
  24.     kPasteI,
  25.     kClearI
  26. };
  27.  
  28. #define bDoOpenCommandOnce    (1L << 0)
  29. #define bDone                (1L << 1)
  30.  
  31. /* *** globals
  32.  */
  33. StringPtr emptyS = "\p";
  34.  
  35. /* forward declarations.
  36.  */
  37. static void HandleEvents(void);
  38.  
  39. /* *** local to this file.
  40.  */
  41. static LongInt localEventSelect = 0;
  42. static DialogPtr progressDlog = NIL;
  43. static OSErr    progressErrCode = noErr;
  44.  
  45. /* *** error routines.
  46.  */
  47.  
  48. /* Error strings
  49.  */
  50. enum{
  51.     kGenericErrS = 1,
  52.     kDirFulErr,        /*Directory full*/
  53.     kDskFulErr,        /*disk full*/
  54.     kNsvErr,        /*no such volume*/
  55.     kIOErr,            /*I/O error*/
  56.     kBdNamErr,        /*there may be no bad names in the final system!*/
  57.     kFnOpnErr,        /*File not open*/
  58.     kEofErr,        /*End of file*/
  59.     kPosErr,        /*tried to position to before start of file (r/w)*/
  60.     kMFulErr,        /*memory full (open) or file won't fit (load)*/
  61.     kTmfoErr,        /*too many files open*/
  62.     kFnfErr,        /*File not found*/
  63.     kWPrErr,        /*diskette is write protected.*/
  64.     kFLckdErr,        /*file is locked*/
  65.     kVLckdErr,        /*volume is locked*/
  66.     kFBsyErr,        /*File is busy (delete)*/
  67.     kDupFNErr,        /*duplicate filename (rename)*/
  68.     kOpWrErr,        /*file already open with with write permission*/
  69.     kRfNumErr,        /*refnum error*/
  70.     kGfpErr,        /*get file position error*/
  71.     kVolOffLinErr,    /*volume not on line error (was Ejected)*/
  72.     kPermErr,        /*permissions error (on file open)*/
  73.     kVolOnLinErr,    /*drive volume already on-line at MountVol*/
  74.     kNsDrvErr,        /*no such drive (tried to mount a bad drive num)*/
  75.     kNoMacDskErr,    /*not a mac diskette (sig bytes are wrong)*/
  76.     kExtFSErr,        /*volume in question belongs to an external fs*/
  77.     kFsRnErr,        /*file system internal error:during rename the old entry was deleted but could not be restored.*/
  78.     kBadMDBErr,        /*bad master directory block*/
  79.     kWrPermErr,        /*write permissions error*/
  80.     kDirNFErr,        /*Directory not found*/
  81.     kTmwdoErr,        /*No free WDCB available*/
  82.     kBadMovErr,        /*Move into offspring error*/
  83.     kWrgVolTypErr,    /*Wrong volume type error [operation not supported for MFS]*/
  84.     kVolGoneErr,    /*Server volume has been disconnected.*/
  85.     kMemFullError    /*Insufficent memory to complete operation.*/
  86. };
  87.  
  88. /* GetErrorStringCode - translate system error code to string index
  89.  */
  90. static Integer GetErrorStringCode(OSErr errCode){
  91.     switch(errCode){
  92.     case noErr:
  93.     case eUserCancel:    return 0;
  94.     case dirFulErr:        return kDirFulErr;        /*Directory full*/
  95.     case dskFulErr:        return kDskFulErr;        /*disk full*/
  96.     case nsvErr:        return kNsvErr;            /*no such volume*/
  97.     case ioErr:            return kIOErr;            /*I/O error*/
  98.     case bdNamErr:        return kBdNamErr;        /*there may be no bad names in the final system!*/
  99.     case fnOpnErr:        return kFnOpnErr;        /*File not open*/
  100.     case eofErr:        return kEofErr;            /*End of file*/
  101.     case posErr:        return kPosErr;            /*tried to position to before start of file (r/w)*/
  102.     case mFulErr:        return kMFulErr;        /*memory full (open) or file won't fit (load)*/
  103.     case tmfoErr:        return kTmfoErr;        /*too many files open*/
  104.     case fnfErr:        return kFnfErr;            /*File not found*/
  105.     case wPrErr:        return kWPrErr;            /*diskette is write protected.*/
  106.     case fLckdErr:        return kFLckdErr;        /*file is locked*/
  107.     case vLckdErr:        return kVLckdErr;        /*volume is locked*/
  108.     case fBsyErr:        return kFBsyErr;        /*File is busy (delete)*/
  109.     case dupFNErr:        return kDupFNErr;        /*duplicate filename (rename)*/
  110.     case opWrErr:        return kOpWrErr;        /*file already open with with write permission*/
  111.     case rfNumErr:        return kRfNumErr;        /*refnum error*/
  112.     case gfpErr:        return kGfpErr;            /*get file position error*/
  113.     case volOffLinErr:    return kVolOffLinErr;    /*volume not on line error (was Ejected)*/
  114.     case permErr:        return kPermErr;        /*permissions error (on file open)*/
  115.     case volOnLinErr:    return kVolOnLinErr;    /*drive volume already on-line at MountVol*/
  116.     case nsDrvErr:        return kNsDrvErr;        /*no such drive (tried to mount a bad drive num)*/
  117.     case noMacDskErr:    return kNoMacDskErr;    /*not a mac diskette (sig bytes are wrong)*/
  118.     case extFSErr:        return kExtFSErr;        /*volume in question belongs to an external fs*/
  119.     case fsRnErr:        return kFsRnErr;        /*file system internal error:during rename the old entry was deleted but could not be restored.*/
  120.     case badMDBErr:        return kBadMDBErr;        /*bad master directory block*/
  121.     case wrPermErr:        return kWrPermErr;        /*write permissions error*/
  122.     case dirNFErr:        return kDirNFErr;        /*Directory not found*/
  123.     case tmwdoErr:        return kTmwdoErr;        /*No free WDCB available*/
  124.     case badMovErr:        return kBadMovErr;        /*Move into offspring error*/
  125.     case wrgVolTypErr:    return kWrgVolTypErr;    /*Wrong volume type error [operation not supported for MFS]*/
  126.     case volGoneErr:     return kVolGoneErr;        /*Server volume has been disconnected.*/
  127.     case memFullErr:    return kMemFullError;
  128.     default:            return kGenericErrS;    
  129.     }
  130. }
  131.  
  132. /* TellError - if an error occurred, report it to the user.
  133.  */
  134. static OSErr TellError(OSErr errCode){
  135.     Str255    errS, s;
  136.     Integer    errN;
  137.  
  138.     if(0 == (errN = GetErrorStringCode(errCode))){
  139.         return errCode;
  140.     }
  141.     GetIndString(errS, kErrorStrs, errN);
  142.     NumToString(errCode, s);
  143.     ParamText(errS, s, emptyS, emptyS);
  144.     Alert(rError, NIL);
  145.     return errCode;
  146. }
  147.  
  148. /* *** progress routines.
  149.  */
  150.  
  151. /* StartProgress - show the progress dialog.
  152.  */
  153. void StartProgress(void){
  154.     if(NIL == progressDlog){
  155.         progressErrCode = noErr;
  156.         progressDlog = GetNewDialog(rProgress, NIL, (WindowPtr) -1L);
  157.         ShowWindow(progressDlog);
  158.         SelectWindow(progressDlog);
  159.         SetPort(progressDlog);
  160.         DrawDialog(progressDlog);
  161.         ValidRect(&progressDlog->portRect);
  162.     }
  163. }
  164.  
  165.  
  166. /* StopProgress - get rid of the prgress dialog.
  167.  */
  168. void StopProgress(void){
  169.     if(NIL != progressDlog){
  170.         DisposeWindow(progressDlog);
  171.         progressDlog = NIL;
  172.     }
  173. }
  174.  
  175. #define kProgressI 3
  176.  
  177. /* BumpProgress - show the progress dialog
  178.  */
  179. OSErr BumpProgress(StringPtr this){
  180.     Integer type;
  181.     Handle    h;
  182.     Rect    r;
  183.  
  184.     if(NIL != progressDlog){
  185.         GetDItem(progressDlog, kProgressI, &type, &h, &r);
  186.         SetIText(h, this);
  187.         HandleEvents();
  188.     }
  189.     return progressErrCode;
  190. }
  191.  
  192.  
  193. /* *** functions.
  194.  */
  195. Integer Min(Integer a, Integer b){ return a < b ? a : b; }
  196.  
  197. /* *** string functions.
  198.  */
  199.  
  200. /* StrMove - 
  201.  */
  202. void StrMove(const StringPtr src, StringPtr dest){
  203.     BlockMove(src, dest, Length(src) + 1);
  204. }
  205.  
  206. /* AppendChar - safe add char to string
  207.  */
  208. void AppendChar(StringPtr s, char c){
  209.     if(Length(s) < 254){
  210.         s[0] = 1 + Length(s);
  211.         s[Length(s)] = c;
  212.     }
  213. }
  214.  
  215. /* Concat - stick the tail on the string
  216.  */
  217. void Concat(StringPtr s, StringPtr tail){
  218.     Integer newLen;
  219.  
  220.     newLen = Min(255, Length(s) + Length(tail));
  221.     BlockMove((Ptr) &tail[1] ,(Ptr) &s[1+Length(s)], newLen - Length(s));
  222.     s[0] = newLen;
  223. }
  224.  
  225.  
  226. /* NullUpdate - the empty update routine.
  227.  */
  228. static pascal void NullUpdate(DialogPtr dp, Integer i){
  229. }
  230.  
  231.  
  232. /* SetWDIHandle - 
  233.  */
  234. static void SetWDIHandle(WindowPtr win, Integer item, Handle h){
  235.     Integer theType;
  236.     Handle theHandle;
  237.     Rect theRect;
  238.  
  239.     GetDItem(win, item, &theType, &theHandle, &theRect);
  240.     SetDItem(win, item, theType, h, &theRect);
  241. }
  242.  
  243. /* SetDIHandle - 
  244.  */
  245. static void SetDIHandle(Integer item, Handle h){
  246.     SetWDIHandle(qd.thePort, item, h);
  247. }
  248.  
  249. /* GetAboutWin - 
  250.  */
  251. static WindowPtr GetAboutWin(void){
  252.     WindowPtr    win;
  253.     DialogTHndl    dt;
  254.  
  255.     if(NIL == (dt = (DialogTHndl) GetResource('DLOG', rAbout))){
  256.         return;
  257.     }
  258.     HNoPurge((Handle) dt);
  259.     win = GetNewDialog(rAbout, NIL, (WindowPtr) -1L);
  260.     SetDIHandle(1, (Handle) NullUpdate);
  261.     ShowWindow(win);
  262.     HPurge((Handle) dt);
  263.     return win;
  264. }
  265.  
  266. /* DoAppleMenu - 
  267.  */
  268. static void DoAppleMenu(Integer item){
  269.     Str255        s;
  270.     WindowPtr    win;
  271.  
  272.     if(1 == item){
  273.         win = GetAboutWin();
  274.         ModalDialog(NIL, &item);
  275.         DisposeWindow(win);
  276.     }else{
  277.         GetItem(GetMHandle(kAppleMenu), item, s);
  278.         OpenDeskAcc(s);
  279.     }
  280. }
  281.  
  282. /* DoOpen - 
  283.  */
  284. static void DoOpen(void){
  285.     StandardFileReply    reply;
  286.     static    OSType    applType[] = { 'APPL', 'rsrc', 'RSRC', 'dfil' };
  287.  
  288.     StandardGetFile(NIL, sizeof(applType)/sizeof(OSType), applType, &reply);
  289.     if(reply.sfGood){
  290.         TellError(Balloonify(&reply.sfFile, reply.sfScript));
  291.     }
  292. }
  293.  
  294. /* DoQuit - do a quit command
  295.  */
  296. static void DoQuit(void){
  297.     ExitToShell();
  298. }
  299.  
  300. /* DoFileMenu - 
  301.  */
  302. static void DoFileMenu(Integer item){
  303.     switch(item){
  304.     case kOpenI:        DoOpen();        break;
  305.     case kQuitI:        DoQuit();        break;
  306.     }
  307. }
  308.  
  309. /* DoEditMenu - 
  310.  */
  311. static void DoEditMenu(Integer item){
  312.     if(NOT SystemEdit(item - 1)){
  313.         switch(item){
  314.         case kUndoI:
  315.         case kCutI:
  316.         case kCopyI:
  317.         case kPasteI:
  318.         case kClearI:
  319.             break;
  320.         }
  321.     }
  322. }
  323.  
  324. /* GoMenu - do one menu command
  325.  */
  326. static void GoMenu(LongInt selector){
  327.     switch(HiWord(selector)){
  328.     case kAppleMenu:    DoAppleMenu(LoWord(selector));    break;
  329.     case kFileMenu:        DoFileMenu(LoWord(selector));    break;
  330.     case kEditMenu:        DoEditMenu(LoWord(selector));    break;
  331.     }
  332.     HiliteMenu(0);
  333. }
  334.  
  335. /* FSSpecFunc - call this with an FSSpecPtr and return an OSErr
  336.  */
  337. typedef OSErr (*FSSpecFunc)(FSSpecPtr);
  338.  
  339. /* BetaExpired - TRUE is later than August 1, 1994
  340. >>>
  341.  */
  342. static Boolean BetaExpired(void){
  343.     return FALSE;
  344. }
  345.  
  346. static void InitPreferences(void){
  347. }
  348.  
  349. /* MissedAEParameters - 
  350.  */
  351. static OSErr MissedAEParameters(AppleEvent *message){
  352.     DescType typeCode;
  353.     Size actualSize;
  354.     OSErr err;
  355.  
  356.     if(errAEDescNotFound == (err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeWildCard,
  357.             &typeCode, NIL, 0L, &actualSize))){
  358.  
  359.         return noErr;
  360.     }
  361.     return (noErr == err ? errAEEventNotHandled : err);
  362. }
  363.  
  364. /* FSOpenWD - convenience function for opening a wRef
  365.  */
  366. static OSErr FSOpenWD(Integer vRef, LongInt dirId, OSType signature, Integer *wRef){
  367.     WDPBRec    io;
  368.     OSErr    val;
  369.  
  370.     io.ioNamePtr    = NIL;
  371.     io.ioVRefNum    = vRef;
  372.     io.ioWDDirID    = dirId;
  373.     io.ioWDProcID    = signature;
  374.     if(noErr == (val = PBOpenWD(&io, FALSE))){
  375.         *wRef = io.ioVRefNum;
  376.     }
  377.     return val;
  378. }
  379.  
  380. /* DirIDVRefToWRef - given a dirId, vRef pair, return the working ref
  381.  */
  382. static OSErr DirIDVRefToWRef(Integer vRef, LongInt dirID, Integer *wRefp){
  383.     return FSOpenWD(vRef, dirID, 'ERIK', wRefp);
  384. }
  385.  
  386.  
  387. static OSErr OpenPrint(AppleEvent *message, AppleEvent *reply, long refCon, FSSpecFunc f){
  388.     FSSpec fss;
  389.     AEDescList docList;
  390.     long index, itemsInList;
  391.     Size actualSize;
  392.     AEKeyword keywd;
  393.     DescType typeCode;
  394.     OSErr err;
  395.     SFReply    sfr;
  396.     FInfo    finfo;
  397.  
  398.     if((err = AEGetParamDesc(message, keyDirectObject, typeAEList, &docList)) != noErr ||
  399.         (err = MissedAEParameters(message)) != noErr ||
  400.         (err = AECountItems(&docList, &itemsInList)) != noErr){
  401.         return err;
  402.     }
  403.  
  404.     for(index = 1; index <= itemsInList; index++){
  405.         if(noErr != (err = AEGetNthPtr(&docList, index, typeFSS, &keywd, &typeCode,
  406.                     (Ptr)&fss, sizeof(FSSpec), &actualSize))){
  407.             break;
  408.         }
  409.         if(noErr != (err = (*f)(&fss))){
  410.             break;
  411.         }
  412.     }
  413.     localEventSelect |= bDone;
  414.     return AEDisposeDesc(&docList);
  415. }
  416.  
  417. /* DoOpenApp - We get this if we weren't given any documents.
  418.     Nothing to do for now in Balloony
  419.  */
  420. static pascal OSErr DoOpenApp(AppleEvent *message, AppleEvent *reply, long refCon){
  421.     OSErr err;
  422.  
  423.     if ((err = MissedAEParameters(message)) != noErr){
  424.         return err;
  425.     }
  426.     localEventSelect |= bDoOpenCommandOnce;
  427.     return noErr;
  428. }
  429.  
  430. /* Balloonify1 - wrapper for balloonify when we don't know the script code.
  431.  */
  432. static OSErr Balloonify1(FSSpecPtr fs){
  433.     return TellError(Balloonify(fs, smSystemScript));
  434. }
  435.  
  436. /* DoOpenDoc
  437.  */
  438. static pascal OSErr DoOpenDoc(AppleEvent *message, AppleEvent *reply, long refCon){
  439.     return OpenPrint(message, reply, refCon, Balloonify1);
  440. }
  441.  
  442. /* DoPrintDoc
  443.  */
  444. static pascal OSErr DoPrintDoc(AppleEvent *message, AppleEvent *reply, long refCon){
  445.     return OpenPrint(message, reply, refCon, Balloonify1);
  446. }
  447.  
  448. /* DoQuitApp - 
  449.  */
  450. static pascal OSErr DoQuitApp(AppleEvent *message, AppleEvent *reply, long refcon){
  451.     OSErr err;
  452.  
  453.     if ((err = MissedAEParameters(message)) != noErr){
  454.         return err;
  455.     }
  456.     localEventSelect |= bDone;
  457.     return noErr;
  458. }
  459.  
  460. static void InitAppleEventHandlers(void){
  461.     LongInt    response;
  462.  
  463.     if(noErr == Gestalt(gestaltAppleEventsAttr, &response) && 
  464.         (response & (1L << gestaltAppleEventsPresent))){
  465.  
  466.         AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, 
  467.                 NewAEEventHandlerProc(DoOpenApp), 0, FALSE);
  468.         AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
  469.                 NewAEEventHandlerProc(DoOpenDoc), 0, FALSE);
  470.         AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
  471.                 NewAEEventHandlerProc(DoPrintDoc), 0, FALSE);
  472.         AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
  473.                 NewAEEventHandlerProc(DoQuitApp), 0, FALSE);
  474.     }
  475. }
  476.  
  477.  
  478. /* Init 
  479.  */
  480. static void Init(void){
  481.     InitGraf((Ptr) &qd.thePort);    /* initialize the toolbox */
  482.     InitFonts();
  483.     InitWindows();
  484.     InitMenus();
  485.     FlushEvents(everyEvent,0);
  486.     TEInit();
  487.     InitDialogs(0L);
  488.     InitCursor();
  489.  
  490.     if(BetaExpired()){
  491.         Alert(kBetaDie, NIL);
  492.         ExitToShell();
  493.     }
  494.     SetMenuBar(GetNewMBar(kMBAR));
  495.     DrawMenuBar();
  496.     AddResMenu(GetMHandle(kAppleMenu), 'DRVR');
  497.     InitBalloonify();
  498.     InitPreferences();
  499.     InitAppleEventHandlers();
  500. }
  501.  
  502. /* GoHighLevelEvent - dispatch to apple event processor
  503.  */
  504. static void GoHighLevelEvent(EventRecord *theEvent){
  505.     AEProcessAppleEvent(theEvent);
  506. }
  507.  
  508.  
  509. /* GoMenuBar - 
  510.  */
  511. static void GoMenuBar(EventRecord *event){
  512.     SetCursor(&qd.arrow);
  513.     GoMenu(MenuSelect(event->where));
  514. }
  515.  
  516. /* GoKey - the keystroke handler
  517.  */
  518. static void GoKey(EventRecord *event){
  519.     WindowPtr    win;
  520.  
  521.     if(cmdKey & event->modifiers){
  522.         GoMenu(MenuKey((char) event->message));
  523.     }
  524. }
  525.  
  526. /* GoMouseDown - the mouse down tracker
  527.  */
  528. static void GoMouseDown(EventRecord *event){
  529.     Integer        sel;
  530.     WindowPtr    win;
  531.  
  532.     sel = FindWindow(event->where, &win);
  533.     switch(sel){
  534.     case inMenuBar:        GoMenuBar(event);            break;
  535.     case inGoAway:        /* GoAway(event, win);    */    break;
  536.     case inDrag:        /* GoDrag(event, win);    */    break;
  537.     case inGrow:        /* GoGrow(event, win);    */    break;
  538.     case inContent:        /* GoContent(event, win);*/    break;
  539.     case inSysWindow:    SystemClick(event, win);    break;
  540.     }
  541. }
  542.  
  543. /* GoIdle - 
  544.  */
  545. static void GoIdle(EventRecord *e){
  546. }
  547.  
  548. /* GoEvent - main event dispatcher.
  549.  */
  550. static void GoEvent(EventRecord *e){
  551.     DialogPtr    dp;
  552.     Integer        item;
  553.  
  554.     if(IsDialogEvent(e) && DialogSelect(e, &dp, &item) &&
  555.         NIL != dp && progressDlog == dp && Cancel == item){
  556.  
  557.         progressErrCode = eUserCancel;
  558.         return;
  559.     }
  560.     switch(e->what){
  561.     case nullEvent:            GoIdle(e);            break;
  562.     case mouseDown:            GoMouseDown(e);        break;
  563.     case autoKey:            
  564.     case keyDown:            GoKey(e);            break;
  565.     case updateEvt:            break;
  566.     case activateEvt:        break;
  567.     case osEvt:                break;
  568.     case kHighLevelEvent:    GoHighLevelEvent(e);    break;
  569.     default:                break;
  570.     }
  571. }
  572.  
  573. /* HandleEvents - 
  574.  */
  575. static void HandleEvents(void){
  576.     EventRecord e;
  577.  
  578.     if(0 != localEventSelect){
  579.         if(localEventSelect & bDone){
  580.             DoQuit();
  581.         }
  582.         if(localEventSelect & bDoOpenCommandOnce){
  583.             localEventSelect &= ~bDoOpenCommandOnce;
  584.             DoOpen();
  585.         }
  586.     }
  587.     WaitNextEvent(everyEvent, &e, NIL, 0);
  588.     GoEvent(&e);    /* allow null event processing */
  589. }
  590.  
  591.  
  592. /* main
  593.  */
  594. main(){
  595.     Init();
  596.     for(;;){
  597.         HandleEvents();
  598.     }
  599.     return 0;
  600. }
  601.